package com.study.project.config.redis;

import java.util.Objects;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.redisson.Redisson;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.JedisPoolConfig;

/**
 * @program: studyProject
 * @description:
 * @author: yangjie
 * @create: 2024-04-13 13:45
 **/
@Configuration
public class RedisConfig {
    @Value(value = "${spring.redis.host}")
    private String host;

    @Value(value = "${spring.redis.port}")
    private Integer port;

    @Value(value = "${spring.redis.database}")
    private Integer db;

    @Value(value = "${spring.redis.password}")
    private String password;

    @Value(value = "${spring.redis.lettuce.pool.max-active}")
    private Integer maxActive;

    @Value(value = "${spring.redis.lettuce.pool.max-idle}")
    private Integer maxIdle;

    @Value(value = "${spring.redis.lettuce.pool.min-idle}")
    private Integer minIdle;

    @Resource
    private RedisConfigProperties redisConfigProperties;

    @Resource
    private LettuceConnectionFactory lettuceConnectionFactory;

    @Bean(destroyMethod = "destroy")
    public RedisClient redisClient() {
        String pwd = StringUtils.hasLength(password) ? password : null;

        JedisPoolConfig config = new JedisPoolConfig();

        config.setMaxIdle(maxIdle);

        config.setMinIdle(minIdle);

        config.setMaxTotal(maxActive);

        return new RedisClient(host, port, pwd, config, db);
    }

    @Bean
    public Redisson redisson() {
        Config config = new Config();
        if (Objects.nonNull(redisConfigProperties.getCluster())) {
            config.useClusterServers().setPassword(redisConfigProperties.getPassword())
                .setNodeAddresses(redisConfigProperties.getCluster().getNodes().stream().map(item -> "redis://" + item)
                    .collect(Collectors.toList()));
        } else {
            config.useSingleServer()
                .setAddress("redis://" + redisConfigProperties.getHost() + ":" + redisConfigProperties.getPort())
                .setPassword(redisConfigProperties.getPassword()).setDatabase(redisConfigProperties.getDatabase());
        }
        return (Redisson)Redisson.create(config);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
            new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        //
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        return redisTemplate;
    }
}